<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>ASCII Art Generator</title>
  <style>
    canvas {
      display: block;
      margin: auto;
    }

    #downloadLink,
    #downloadJpgLink {
      display: none;
      margin-top: 10px;
    }
  </style>
</head>
<body>

  <h1>ASCII Art Generator</h1>
  <input type="file" id="imageLoader" name="imageLoader" />
  <br />
  <br />
  <canvas id="asciiCanvas"></canvas>
  <br />
  <br />
  <a id="downloadLink" href="#" style="margin-right: 20px;">下载图片(PNG)</a>
  
  <a id="downloadJpgLink" href="#">下载图片(JPG 白色背景)</a>

  <script>
    window.onload = function () {
      const imageLoader = document.getElementById('imageLoader');
      const asciiCanvas = document.getElementById('asciiCanvas');
      const downloadLink = document.getElementById('downloadLink');
      const downloadJpgLink = document.getElementById('downloadJpgLink');

      imageLoader.onchange = e => {
        const file = e.target.files[0];
        if (!file) return;

        const img = new Image();
        const reader = new FileReader();

        reader.onload = event => {
          img.onload = () => {
            convertToAsciiArt(img, asciiCanvas);
          };
          img.src = event.target.result;
        };

        reader.readAsDataURL(file);
      };

      function convertToAsciiArt(image, canvas) {
        const charWidth = 4; // 假设每个字符的宽度为6像素
        const charHeight = 8; // 假设每个字符的高度为12像素（即2:1的比例）

        // 根据字符宽高比调整输出尺寸，保持原始宽高比
        let width = Math.floor(image.width / charWidth);
        let height = Math.floor(image.height / charHeight);

        // 确保不超出画布的最大尺寸
        const maxWidth = 80; // 最大字符宽度
        if (width > maxWidth) {
          height = Math.floor(height * (maxWidth / width));
          width = maxWidth;
        }

        canvas.width = width * charWidth;
        canvas.height = height * charHeight;
        const ctx = canvas.getContext('2d');

        // 清除画布并设置字体样式
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.font = `${charHeight}px monospace`;
        ctx.textBaseline = 'top';

        // 将画布内容转换为灰度图像数据
        ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
        const asciiArt = [];
        for (let y = 0; y < height; ++y) {
          let line = '';
          for (let x = 0; x < width; ++x) {
            const index = (y * charHeight * canvas.width + x * charWidth) * 4;
            const gray = (imageData[index] + imageData[index + 1] + imageData[index + 2]) / 3;
            line += getChar(gray);
          }
          asciiArt.push(line);
        }

        // 清除画布，准备绘制ASCII艺术
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // 绘制ASCII艺术到画布
        asciiArt.forEach((line, i) => {
          ctx.fillText(line, 0, i * charHeight);
        });

        // 创建PNG下载链接（透明背景）
        canvas.toBlob(blob => {
          const url = URL.createObjectURL(blob);
          downloadLink.href = url;
          downloadLink.download = 'ascii_art.png';
          downloadLink.style.display = 'inline';
        }, 'image/png'); // 不需要额外参数，因为PNG支持透明

        // 创建JPEG下载链接（带白色背景）
        // 先绘制白色背景
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // 设置文本颜色为黑色并在白色背景上绘制ASCII艺术
        ctx.fillStyle = 'black'; // 设置文本颜色为黑色
        asciiArt.forEach((line, i) => {
          ctx.fillText(line, 0, i * charHeight);
        });

        canvas.toBlob(blob => {
          const url = URL.createObjectURL(blob);
          downloadJpgLink.href = url;
          downloadJpgLink.download = 'ascii_art.jpg';
          downloadJpgLink.style.display = 'inline';
        }, 'image/jpeg', 1.0); // 第三个参数是质量，范围是0到1
      }

      function getChar(gray) {
        // 这里可以根据灰度值返回不同的字符，形成渐变效果
        const chars = " .`^\",:;Il!i~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$"; // 从最浅到最深
        const index = Math.floor(chars.length * gray / 256);
        return chars[index] || chars[chars.length - 1];
      }
    };
  </script>

</body>
</html>